Coverage Report

Created: 2024-12-19 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\tools.proto\tools.proto\runtime\src\codec\bytes.rs
Line
Count
Source
1
// Copyright (c) 2024, BlockProject 3D
2
//
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification,
6
// are permitted provided that the following conditions are met:
7
//
8
//     * Redistributions of source code must retain the above copyright notice,
9
//       this list of conditions and the following disclaimer.
10
//     * Redistributions in binary form must reproduce the above copyright notice,
11
//       this list of conditions and the following disclaimer in the documentation
12
//       and/or other materials provided with the distribution.
13
//     * Neither the name of BlockProject 3D nor the names of its contributors
14
//       may be used to endorse or promote products derived from this software
15
//       without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
use bytesutil::{ReadBytes, WriteBytes};
30
31
pub trait ByteCodec {
32
    /// Reads a value of type T from the buffer argument assuming the buffer size is greater or
33
    /// equal to the size of T.
34
    ///
35
    /// # Arguments
36
    ///
37
    /// * `buffer`: the buffer to read from.
38
    ///
39
    /// returns: T
40
    ///
41
    /// # Safety
42
    ///
43
    /// This function assumes that the length of the buffer passed in as argument is at least as
44
    /// large as the size of T. Currently, this relies on bytesutil which does not apply any
45
    /// optimization and as such passing a too small buffer will only panic, however a future
46
    /// optimization might remove the panic check from release builds, essentially causing UB in
47
    /// such build.
48
    unsafe fn read_aligned<T: ReadBytes>(buffer: &[u8]) -> T;
49
50
    /// Reads a value of type T from the buffer argument assuming the buffer size is always less
51
    /// than the size of T. This is not unsafe as will always cause a copy into an 8 bytes buffer
52
    /// (the maximum size for T is 8).
53
    ///
54
    /// # Arguments
55
    ///
56
    /// * `buffer`: the buffer to read from.
57
    ///
58
    /// returns: T
59
    fn read_unaligned<T: ReadBytes>(buffer: &[u8]) -> T;
60
61
7
    fn read<T: ReadBytes>(buffer: &[u8]) -> T {
62
7
        if size_of::<T>() != buffer.len() {
  Branch (62:12): [True: 0, False: 1]
  Branch (62:12): [Folded - Ignored]
  Branch (62:12): [True: 0, False: 4]
  Branch (62:12): [True: 2, False: 0]
63
2
            Self::read_unaligned::<T>(buffer)
64
        } else {
65
5
            unsafe { Self::read_aligned::<T>(buffer) }
66
        }
67
7
    }
68
69
    /// Writes a value of type T in the buffer argument assuming the buffer size is greater or
70
    /// equal to the size of T.
71
    ///
72
    /// # Arguments
73
    ///
74
    /// * `buffer`: the buffer to write to.
75
    /// * `value`: the value to write.
76
    ///
77
    /// # Safety
78
    ///
79
    /// This function assumes that the length of the buffer passed in as argument is at least as
80
    /// large as the size of T. Currently, this relies on bytesutil which does not apply any
81
    /// optimization and as such passing a too small buffer will only panic, however a future
82
    /// optimization might remove the panic check from release builds, essentially causing UB in
83
    /// such build.
84
    unsafe fn write_aligned<T: WriteBytes>(buffer: &mut [u8], value: T);
85
86
    fn write_unaligned<T: WriteBytes>(buffer: &mut [u8], value: T);
87
88
6
    fn write<T: WriteBytes>(buffer: &mut [u8], value: T) {
89
6
        if size_of::<T>() != buffer.len() {
  Branch (89:12): [Folded - Ignored]
  Branch (89:12): [Folded - Ignored]
  Branch (89:12): [True: 0, False: 4]
  Branch (89:12): [True: 2, False: 0]
90
2
            Self::write_unaligned::<T>(buffer, value);
91
4
        } else {
92
4
            unsafe { Self::write_aligned::<T>(buffer, value) };
93
4
        }
94
6
    }
95
}
96
97
pub struct ByteCodecBE;
98
pub struct ByteCodecLE;
99
100
impl ByteCodec for ByteCodecLE {
101
205
    unsafe fn read_aligned<T: ReadBytes>(buffer: &[u8]) -> T {
102
205
        T::read_bytes_le(buffer)
103
205
    }
104
105
2
    fn read_unaligned<T: ReadBytes>(buffer: &[u8]) -> T {
106
2
        let mut data = [0; 8];
107
2
        data[..buffer.len()].copy_from_slice(buffer);
108
2
        unsafe { Self::read_aligned::<T>(&data) }
109
2
    }
110
111
141
    unsafe fn write_aligned<T: WriteBytes>(buffer: &mut [u8], value: T) {
112
141
        value.write_bytes_le(buffer);
113
141
    }
114
115
2
    fn write_unaligned<T: WriteBytes>(buffer: &mut [u8], value: T) {
116
2
        let mut data = [0; 8];
117
2
        data[..buffer.len()].copy_from_slice(buffer);
118
2
        unsafe { Self::write_aligned::<T>(&mut data, value) };
119
2
        let motherfuckingrust = buffer.len();
120
2
        buffer.copy_from_slice(&data[..motherfuckingrust]);
121
2
    }
122
}
123
124
impl ByteCodec for ByteCodecBE {
125
0
    unsafe fn read_aligned<T: ReadBytes>(buffer: &[u8]) -> T {
126
0
        T::read_bytes_be(buffer)
127
0
    }
128
129
0
    fn read_unaligned<T: ReadBytes>(buffer: &[u8]) -> T {
130
0
        let offset = size_of::<T>() - buffer.len();
131
0
        let mut data = [0; 8];
132
0
        data[offset..buffer.len() + offset].copy_from_slice(buffer);
133
0
        unsafe { Self::read_aligned::<T>(&data) }
134
0
    }
135
136
0
    unsafe fn write_aligned<T: WriteBytes>(buffer: &mut [u8], value: T) {
137
0
        value.write_bytes_be(buffer);
138
0
    }
139
140
0
    fn write_unaligned<T: WriteBytes>(buffer: &mut [u8], value: T) {
141
0
        let offset = size_of::<T>() - buffer.len();
142
0
        let mut data = [0; 8];
143
0
        data[offset..buffer.len() + offset].copy_from_slice(buffer);
144
0
        unsafe { Self::write_aligned::<T>(&mut data, value) };
145
0
        let motherfuckingrust = buffer.len();
146
0
        buffer.copy_from_slice(&data[offset..motherfuckingrust + offset]);
147
0
    }
148
}
149
150
#[cfg(test)]
151
mod tests {
152
    use crate::codec::{ByteCodec, ByteCodecLE};
153
154
    #[test]
155
1
    fn basic() {
156
1
        let buffer = [0xFF, 0xFF, 0xFF, 0xFF];
157
1
        assert_eq!(ByteCodecLE::read::<u32>(&buffer[0..4]), 0xFFFFFFFF);
158
1
    }
159
}